前天我們寫好了 create_app
,但是還沒有人呼叫他,今天我們就要來呼叫他 (當然還不能用啦,因為藍圖都沒寫好)。
這個檔案叫做 manage.py
,顧名思義,他就是用來管理的,我們可以用它來操作這個 application 及其附屬的資源,像是資料庫等等。而他是會用 flask 這個指令來操作 (跟 flask run
同一個),我們預計會加入以下幾個指令:
init_db
會把資料庫初始化,但如果本來就存在他不會亂動。reset_db
會把資料庫整個砍掉再重建。create_user
會用來新增一個使用者,當然也可以透過設定 is_admin=True
來讓它變成管理員。事不宜遲,我們就開始吧。但在開始之前我們要先寫一下 manage.py
的基本架構。後面我們會執行他,所以也會連帶執行到之前的 create_app
,如果想看他正常執行的話,要先把那幾行藍圖的程式碼註解掉,不然會跑錯誤,畢竟我們根本沒定義過他們。
from os import getenv
from app import create_app, db
app = create_app(getenv("FLASK_ENV"))
@app.shell_context_processor
def make_shell_context():
return globals()
我們在最一開始引入了 getenv
,這是之前很熟悉的函式了。接著還有 create_app
和 db
,後者在今天不會用到,只是先引入留著,之後會用到。
接著我們用 create_app
造出了一個 app
,使用的參數是環境變數 FLASK_ENV
,所以自己要先設定好這個環境變數。
最後三行是 flask 提供的一個可以方便 debug 的小工具,他可以執行 flask 然後開一個 shell 讓你跟他互動,可以查現在 app
裡面有什麼內容之類的。使用的方式也很簡單,用 flask shell
這個指令即可,他就會開一個 shell 給你用。但這時候使用他會噴錯誤,我們等等還需要設定一個環境變數來處理。要使用這個 shell 是不需要這三行的,flask 本來就可以直接用,他們的用意是把現在的環境直接複製到 shell 裡面,讓 shell 可以看的資訊更多 (整個 globals()
),他這邊用到了 context 這個詞,如果深入鑽研的話會一直看到他,但在此處就先不提。可以試試看不加這三行,可以很明顯地發現如果不加然後在 shell 使用 create_app
會出現未定義。
這時候可能會想,我們根本沒有 app.run()
或是類似的函式,那他要怎麼執行?我們需要先設定 FLASK_APP
這個環境變數,它是用來告知 flask 我們的 app
在哪裡的。以此處為例,我們需要把它設為 manage.py
,這樣 flask 就會知道我們的 app
就放在 manage.py
裡面,然後他就會自動自發地執行他。設定完成之後,flask shell
應該就可以使用了,可以嘗試看看。
但我們當然不是要執行 shell,我們需要讓他真的跑起來讓大家都可以用,所以我們就需要用之前用過的 flask run
來讓他跑起來,如同上面所述,它會自動去抓 app
然後讓他跑起來。
因為這些新指令都是有關資料庫的,所以在加入新的指令到 manage.py
之前,我們必須先寫好資料庫端的函式,基本上就是不要讓 db
離開 app/database
。我們需要先多開一個 helper.py
放在 app/database
,然後加入一些函式給外部引入。
from .models import db, Users
def init():
db.create_all()
def reset():
db.drop_all()
db.create_all()
def add_user(username, password, email, introduction=None, is_admin=False):
user = Users(username, password, email, introduction, is_admin)
try:
db.session.add(user)
db.session.commit()
return True
except:
return False
這邊加入了三個函式,我們一個一個看。記得也要在 app/database/__init__.py
加入 from .helper import init, reset, add_user
。
init
是用來初始化資料庫的,我們使用 create_all
這個函式來幫忙,他會幫我們把資料庫的 table 都建好,但如果已經存在的話,他不會把資料刪掉。reset
是用來把資料刪光光並重新建好資料庫的,我們使用 drop_all
和 create_all
,分別會把資料都刪光及建立資料庫,所以把他們兩個一起用就可以達到重設的目的了。add_user
是用來新增使用者的函式,要建立一個使用者很簡單,就只要用我們給的參數建立一個 Users
物件即可 (最前面引入了),接下來我們用 try ... except ...
來避免錯誤,沒錯誤就回傳 True
,反之 False
,當然可以做得更細緻 (判斷使用者名稱是否重複等等),但這邊就展示性質,不處理其他狀況。這邊我們使用 db.session.add
來把這個使用者加入到 session
裡面,接著再 db.session.commit
把這個變化寫入資料庫。結束資料庫端的函式之後,我們可以看看 manage.py
要怎麼接。要記得最前面需要引入 from app.database import init, reset, add_user
。
@app.cli.command(name="init_db")
def init_db():
init()
@app.cli.command(name="reset_db")
def reset_db():
reset()
@app.cli.command(name="create_user")
def create_user():
username = input("Username: ")
password = input("Password: ")
email = input("Email: ")
is_admin = True if input("Is admin or not (y or n): ") == "y" else False
if add_user(username, password, email, None, is_admin):
print("OK")
else:
print("Failed")
這裡我們使用了 app.cli.command
這個裝飾器,flask 的這個部分是用 click
實作的,所以會有一些點跟他一樣,像是函式名稱是 create_user
但要呼叫的時候需要用 create-user
,我自己是習慣把它改掉,使用 name
這個參數。
init_db
的部分基本上就是剛剛的 init
,不管他。reset
也跟剛剛一樣,不管他。create_user
我們用 input
的方式讓人輸入資料,然後加入。這裡可以自己加入 email 的判斷、密碼長度是否過短之類的偵測,這邊就不大費周章了。
把他們加入完之後,就可以直接用 flask 來執行,我們可以先 flask init_db
讓他初始化資料庫,然後 flask add_user
新增一個使用者,沒有意外的話應該都可以跑得很順利。
Command Line Interface
Session Basics
請問"manage.py"是放在那裏?
直接放在最外層的目錄就好
建議可以直接看 repo 會比較清楚